<?php
	
use \GatewayWorker\Lib\Gateway;

include_once(dirname(__DIR__) .'/Module/Verification.class.php');
include_once(dirname(__DIR__) .'/Module/Socket.class.php');
include_once(dirname(__DIR__) .'/Module/Redis.class.php');
require_once dirname(__DIR__) . '/base.class.model.php';
class Public_Model extends Base_Model
{

	//扣除房卡或退还房卡
	protected function balanceTicket($room_id, $account_id, $spend_ticket_count){
		$timestamp = time();
		$MMYSQL = $this->initMysql();
		$MMYSQL->update(Room_Ticket)->set("ticket_count", "ticket_count-".$spend_ticket_count)->where("account_id=".$account_id)->query();

		//获取流水账
		$balance = 0;
		$balance_where = 'account_id='.$account_id.' and is_delete=0';
		$balance_sql = 'select balance from '.Room_Ticket_Journal.' where '.$balance_where.' order by journal_id desc';

		$balance_query = $MMYSQL->query($balance_sql);
		if(is_array($balance_query) && count($balance_query) > 0 ){
			$balance = $balance_query[0]['balance'];
		}

		//添加到流水账
		$journal_array['create_time'] = $timestamp;
		$journal_array['create_appid'] = "aid_".$account_id;
		$journal_array['update_time'] = $timestamp;
		$journal_array['update_appid'] = "aid_".$account_id;
		$journal_array['is_delete'] = G_CONST::IS_FALSE;
		$journal_array['account_id'] = $account_id;
		$journal_array['object_id'] = $room_id;
		$journal_array['object_type'] = 3;  //游戏

		$journal_array['extra'] = "";
		if($spend_ticket_count > 0){
			$journal_array['disburse'] = $spend_ticket_count;
			$journal_array['abstract'] = "滚轮子";		//摘要
		} else {
			$journal_array['income'] = -$spend_ticket_count;
			$journal_array['abstract'] = "滚轮子房卡退还";		//摘要
		}

		$journal_array['balance'] = $balance - $spend_ticket_count;
		if($journal_array['balance'] < 0)
		{
			$this->writeLog("[$room_id]($account_id) balance negative balance: ".$balance);
			$journal_array['balance'] = 0;
		}
		$journal_id = $MMYSQL->insertReturnID(Room_Ticket_Journal,$journal_array);
		return;
	}
	
	//开局
	protected function startGame($room_id, $passive_by_timer=false)
	{
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);

		$room_status = $this->queryRoomStatus($room_id);
		if($room_status == Game::RoomStatus_Playing)
		{
			return false;
		}

		$banker_id = $this->queryBanker($room_id);
		$game_num = $this->queryGameNumber($room_id);


		$room_rule = $this->queryRoomRule($room_id); 
		$banker_mode = $room_rule['banker_mode'];
		//大于一个回合，庄家不准备不开始游戏
		if($banker_mode == Game::BankerMode_FixedBanker && $game_num >= 1)
		{
			$banker_online_status = $this->queryOnlineStatus($room_id, $banker_id);
			$banker_status = $this->queryAccountStatus($room_id, $banker_id);
			if($banker_status != Game::AccountStatus_Ready || $banker_online_status == 0)
			{
				$this->writeLog("[$room_id] 庄家".$banker_id." 未准备 不能开局");
				return false;
			}
		}

		//准备的人
		$ready_user = $this->queryReadyUser($room_id);
		//获取在桌上的人
		$at_table_user = $this->queryTableUser($room_id);

		$ready_count = count($ready_user);
		$at_table_count = count($at_table_user);


		//准备人数 大于等于2 且 准备人数 等于 在线人数
		$this->writeLog("[$room_id] 准备:".$ready_count."人   "."在桌:".$at_table_count."人");

		if($ready_count >=2)
		{
			if($passive_by_timer || $ready_count == $at_table_count ){

				$room_members = $this->queryRoomMembers($room_id);
				
				$success = $this->setHashTransaction($room_id);
				if(!$success){
					$this->writeLog("并发 start game，忽略。room id:".$room_id."。in file".__FILE__." on Line ".__LINE__);
					return false;
				}

				if(!$passive_by_timer){
					//取消倒计时
					$this->deleteRoomTimer($room_id);
				}

				//开始游戏
				//扣房卡
				$ticket_checked_user = $this->queryTicketCheckedUser($room_id);
				$to_check_user_array = array_diff($room_members, $ticket_checked_user);

				if(count($to_check_user_array) > 0)
				{
					$spend_ticket_count = $this->queryTicketCount($room_id);

					foreach ($to_check_user_array as $account_id) 
					{
						if(Game::PaymentType_AA == Config::Ticket_Mode){
							//扣除房卡
							$this->balanceTicket($room_id, $account_id, $spend_ticket_count);
						}
						
						$mkv[$account_id] = $spend_ticket_count;
					}

					$TicketChecked_Key = strtr(Redis_Const::TicketChecked_Key, $replyArr);
					$Redis_Model->hmsetField($TicketChecked_Key,$mkv);
				}

				$ShowCard_Key = strtr(Redis_Const::ShowCard_Key, $replyArr);
				$Card_Key = strtr(Redis_Const::Card_Key, $replyArr);
				$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
				

				//删除每局玩家下注筹码hash
				$Chip0_Key = strtr(Redis_Const::Chip0_Key, $replyArr);
				$Chip1_Key = strtr(Redis_Const::Chip1_Key, $replyArr);
				$Chip2_Key = strtr(Redis_Const::Chip2_Key, $replyArr);
				$Chip3_Key = strtr(Redis_Const::Chip3_Key, $replyArr);
				$Redis_Model->deleteKey($Chip0_Key);
				$Redis_Model->deleteKey($Chip1_Key);
				$Redis_Model->deleteKey($Chip2_Key);
				$Redis_Model->deleteKey($Chip3_Key);
				//删除每局玩家摊牌标识hash
				$Redis_Model->deleteKey($ShowCard_Key);
				//删除每局玩家手牌hash
				$Redis_Model->deleteKey($Card_Key);

				//删除每局玩家抢庄hash
				if($banker_mode == Game::BankerMode_FreeGrab)
				{
					$Grab_Key = strtr(Redis_Const::Grab_Key, $replyArr);
					$Redis_Model->deleteKey($Grab_Key);
				}


				$AccStatus_mvk = array();

				$Cards = $this->dealCard($room_id);  //发牌

				for ($i=0; $i < 4; $i++) {

						if(isset($room_members[$i])){
								$account_id = $room_members[$i];
								//玩家状态变成选择抢庄状态
								$AccStatus_mvk[$account_id] = Game::AccountStatus_Choose;

								$player_status[] = array(
									"account_id"=> $account_id,
							        "account_status"=> Game::AccountStatus_Choose,		 //5; 初始是选择抢庄
							        "online_status" => $this->queryOnlineStatus($room_id, $account_id),
							        "limit_time" => Game::LimitTime_Grab
								);
					}
				}

				//$mset_result = $Redis_Model->hmsetField($Chip_Key,$Chip_mkv);
				$mset_result = $Redis_Model->hmsetField($AccountStatus_Key,$AccStatus_mvk);

				//重设每局游戏参数
				//$parameter_ary[Redis_CONST::Play_Field_Banker] = -1;
				$parameter_ary[Redis_CONST::Play_Field_Circle] = -1;
				$mset_result = $Redis_Model->hmsetField($Play_Key,$parameter_ary);

				//房间轮数与局数更新
				$game_num = $this->updateGameNumberRound($room_id);

				if($banker_mode == Game::BankerMode_FreeGrab  || $game_num == 1){
					//推送开始
					$arr = array("result"=>0,"operation"=>"GameStart","data"=>$player_status,"result_message"=>"游戏开始了","limit_time" => Game::LimitTime_Grab,"game_num" => $game_num);
					$this->pushMessageToGroup($room_id, $arr);
					//设置叫庄回合
					$this->updateCircle($room_id,Game::Circle_Grab);
					//设置自动不叫庄定时器
					$this->setupGrabPassiveTimer($room_id);
				} else {
					$this->startShuffleRound($room_id);
				}


			} else {

					if($Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_ReadyTime) == -1 ){
						//只有第二个人的准备才触发倒计时
						$is_pushTimer = true;
						$this->setupStartGamePassiveTimer($room_id,$is_pushTimer);
					}
			}
		}
		
		return true;
	}


	//抢庄回合结束，开启下注回合
	protected function grabPassiveOpt($room_id)
	{
		//设置用户状态
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
		$mkv = array();
		$player_array = $this->queryPlayMember($room_id);
		if(is_array($player_array) && count($player_array)){
			foreach ($player_array as $account_id) {
				$pre_status = $this->queryAccountStatus($room_id, $account_id);
				if($pre_status == Game::AccountStatus_Choose)
				{
					$mkv[$account_id] = Game::AccountStatus_Notgrab;	//默认不抢
				}
			}
		}
		if(count($mkv) > 0)
		{
			$mset_result = $Redis_Model->hmsetField($AccountStatus_Key,$mkv);  //用户状态
		}
		//选择庄家，开始下注回合
		$this->startShuffleRound($room_id);

		return true;
	}

	/*
		选择庄家 洗牌回合
	*/
	protected function startShuffleRound($room_id)
	{
		$room_rule = $this->queryRoomRule($room_id); 
		$banker_mode = $room_rule['banker_mode'];
		$game_num = $this->queryGameNumber($room_id);
		//$pre_circle = $this->queryCircle($room_id);
		if($banker_mode == Game::BankerMode_FixedBanker && $game_num > 1){
			$pre_circle = -1;
			$update_circle = Game::Circle_Shuffle;
			$this->writeLog("[$room_id] 第".$game_num."局开始，即将洗牌");
		} else {
			$pre_circle = Game::Circle_Grab;
			$update_circle = Game::Circle_Shuffle;
			$this->writeLog("[$room_id] 第".$game_num."局 选庄完毕，即将洗牌");
		}

		$success = $this->setCircleTransaction($room_id,$pre_circle,$update_circle);
		if(!$success)
		{
			$this->logMessage('error', "function(startShuffleRound):并发忽略。room id:".$room_id." in file".__FILE__." on Line ".__LINE__);
			return false;
		}

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);

		$grab_array = array();
		$mult_array = array();
		$max_mult = 1;
		
		//获取所有游戏用户
		$player_array = $this->queryPlayMember($room_id);

		if($banker_mode == Game::BankerMode_FixedBanker && $game_num > 1)
		{
			$banker_id = $this->queryBanker($room_id);
			$is_only = G_CONST::IS_TRUE;

			foreach($player_array as $player_id)
			{
				//设置用户状态
				$this->updateAccountStatusNotNoty($room_id, $player_id, Game::AccountStatus_Shuffle);
			}
		}
		else
		{
			foreach($player_array as $player_id)
			{
				$banker_mult = $this->queryGrabMultiples($room_id, $player_id);

				if($banker_mult != false)
				{
					$mult_array[$banker_mult][] = $player_id;
					if($banker_mult > $max_mult)
					{
						$max_mult = $banker_mult;
					}
				}
				//设置用户状态
				$this->updateAccountStatusNotNoty($room_id, $player_id, Game::AccountStatus_Shuffle);
			}

			if(isset($mult_array[$max_mult]) && count($mult_array[$max_mult]) >0)
			{
				$grab_array = $mult_array[$max_mult];
			}

			$is_only = G_CONST::IS_FALSE;
			if(count($grab_array) == 1)
			{
				$is_only = G_CONST::IS_TRUE;
			}

			if(count($grab_array) == 0)
			{
				$this->writeLog("[$room_id] 无人抢庄");
				//无人上庄，重新开局
				//设置房间轮数为0
				if($banker_mode == Game::BankerMode_FixedBanker){
					$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
					$r_mkv[Redis_Const::Room_Field_GameNum] = 0;			//游戏局数
					$r_mkv[Redis_Const::Room_Field_Status] = Game::RoomStatus_Waiting;
					$mset_result = $Redis_Model->hmsetField($Room_Key,$r_mkv);

					$ticket_checked_user = $this->queryTicketCheckedUser($room_id);
					foreach($ticket_checked_user as $player_id)
					{
						//设置用户状态为已准备
						$this->updateAccountStatusNotNoty($room_id, $player_id, Game::AccountStatus_Ready);
					}
					
					$this->startGame($room_id, true);
					return true;
				} else if($banker_mode == Game::BankerMode_FreeGrab){
					//$grab_array = $player_array;
					//选取桌上在线的玩家
					//$player_array = array_slice($player_array, 0, 4);
					$player_array = $this->queryInSeatPlayer($room_id);
					/*						$tmp_arr = array();
					foreach ($player_array as $account_id) {
						if($this->queryOnlineStatus($room_id, $account_id)){
							$tmp_arr[] = $account_id;
						}
					}
					if(count($tmp_arr) > 0){
						$grab_array = $tmp_arr;
					} else {
						$grab_array = $player_array;
					}*/
					$ticket_checked_user = $this->queryTicketCheckedUser($room_id);
					$base_arr = array_intersect($player_array,$ticket_checked_user);
					//从中优选抽取在线
					$priority_arr = array();
					foreach($base_arr as $account_id){
						if($this->queryOnlineStatus($room_id,$account_id)){
							$priority_arr[] = $account_id;
						}
					}
					if(count($priority_arr) > 0){
						$grab_array = $priority_arr;
					} else {
						$grab_array = array_values($base_arr);
					}
				}

			}
			
			//选择庄家
			$banker_num = rand(0,count($grab_array)-1);
			$banker_id = $grab_array[$banker_num];

			//设置banker
			$this->updateBanker($room_id,$banker_id);

			//庄家必须已检票
			if($this->queryTicketChecked($room_id,$banker_id) != 1){
				$TicketChecked_key = strtr(Redis_CONST::TicketChecked_Key,$replyArr);
				$Redis_Model->hmgetField($TicketChecked_key,array($banker_id=>1));
			}
		}

		//设置banker分数
		if($banker_mode == Game::BankerMode_FixedBanker && $game_num == 1)
		{
			$banker_score = $this->queryBankerScore($room_id);
			$this->updateAccountScore($room_id, $banker_id,$banker_score);
		}

		//天门自动洗牌
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$banker_seat_number = $Redis_Model->getZscore($RoomSequence_Key, $banker_id);

		$tianmen_seat_number = $banker_seat_number < 3 ? ($banker_seat_number + 2) : ($banker_seat_number - 2);
		$tianmen_id = -1;
		$zrange_array['is_zrange'] = true;
		$zrange_array['key'] = $RoomSequence_Key;
		$zrange_array['start'] = 0;
		$zrange_array['stop'] = -1;
		$zrange_array['WITHSCORES'] = 1;
		$members = $Redis_Model->zrangeSet($zrange_array);
		if(is_array($members) ){
			foreach ($members as $account_id => $seat_number) {
				if($seat_number == $tianmen_seat_number){
					$tianmen_id = $account_id;
				}
			}
		}

		if($tianmen_id > 0){
			$limit_time = Game::LimitTime_Shuffle;
		} else {
			$limit_time = 0;
		}
		//设置自动洗牌定时器
		$this->setupShufflePassiveTimer($room_id, $limit_time, $is_only);
		$banker_id = $this->queryBanker($room_id);
		$arr = array("result"=>0,"operation"=>"NotyShuffle","data"=>array('banker_id'=>$banker_id),"result_message"=>"通知洗牌","limit_time" => $limit_time);
		$this->pushMessageToGroup($room_id, $arr);
		
		return true;
	}

    //获取在桌用户 1 2 3 4
    protected function queryInSeatPlayer($room_id){
        $Redis_Model = Redis_Model::getModelObject();
        $replyArr = array("[roomid]"=>$room_id);
        $RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
        $arr['key'] = $RoomSequence_Key;
        $arr['min'] = 1;
        $arr['max'] = 4;
        $members = $Redis_Model->getSortedSetLimitByAry($arr);
        if(is_array($members) ){
            return $members;
        } else {
            return array();
        }
    }


	/*
		开始下注回合
	*/
	protected function startBetRound($room_id)
	{
		$pre_circle = $this->queryCircle($room_id);
		if($pre_circle == Game::Circle_Shuffle){
			$update_circle = Game::Circle_Bet;
			$this->writeLog("[$room_id] 洗牌完毕，即将(上半场)下注");
		} else if($pre_circle == Game::Circle_Pause){
			$update_circle = Game::Circle_Bet2;
			$this->writeLog("[$room_id] 中场完毕，即将(下半场)下注");
		} else {
			$this->writeLog("[$room_id] 前状态错误");
			return false;
		}
		
		$success = $this->setCircleTransaction($room_id,$pre_circle,$update_circle);
		if(!$success)
		{
			$this->logMessage('error', "function(startBetRound):并发忽略。room id:".$room_id." in file".__FILE__." on Line ".__LINE__);
			return false;
		}

		$player_array = $this->queryPlayMember($room_id);
		foreach($player_array as $player_id)
		{
			//设置用户状态为下注中
			$this->updateAccountStatusNotNoty($room_id, $player_id, Game::AccountStatus_Bet);
		}

		//设置自动下注定时器
		$this->setupBetPassiveTimer($room_id);

		//通知用户下注
		$arr = array("result"=>0,"operation"=>"StartBet","data"=>array(),"result_message"=>"投注开始了","limit_time" => Game::LimitTime_Betting);
		$this->pushMessageToGroup($room_id, $arr);
	}


	/*
		开始发牌回合
	*/
	protected function startDealRound($room_id)
	{
		$pre_circle = $this->queryCircle($room_id);
		if($pre_circle == Game::Circle_Bet){
			$update_circle = Game::Circle_Deal;
			$this->writeLog("[$room_id] (上半场)下注完毕，即将发牌");
		} else if($pre_circle == Game::Circle_Bet2){
			$update_circle = Game::Circle_Deal2;
			$this->writeLog("[$room_id] (下半场)下注完毕，即将发牌");
		} else {
			$this->writeLog("[$room_id] startDealRound前状态错误");
			return false;
		}

		$success = $this->setCircleTransaction($room_id,$pre_circle,$update_circle);
		if(!$success)
		{
			$this->logMessage('error', "function(startBetRound):并发忽略。room id:".$room_id." in file".__FILE__." on Line ".__LINE__);
			return false;
		}

		$player_array = $this->queryPlayMember($room_id);
		foreach($player_array as $player_id)
		{
			$this->updateAccountStatusNotNoty($room_id, $player_id, Game::AccountStatus_Deal);
		}

		//设置自动发牌定时器
		$this->setupDealPassiveTimer($room_id);

		//通知用户下注
		$arr = array("result"=>0,"operation"=>"NotyDealCard","data"=>array(),"result_message"=>"通知发牌","limit_time" => Game::LimitTime_Deal);
		$this->pushMessageToGroup($room_id, $arr);
	}

	/*
		发牌，推送摊牌回合
	*/
	protected function startShowRound($room_id)
	{
		$pre_circle = $this->queryCircle($room_id);
		if($pre_circle == Game::Circle_Deal){
			$update_circle = Game::Circle_Show;
			$this->writeLog("[$room_id] (上半场)发牌完毕，即将摊牌");
			$offset = 0;
		} else if($pre_circle == Game::Circle_Deal2){
			$update_circle = Game::Circle_Show2;
			$this->writeLog("[$room_id] (下半场)发牌完毕，即将摊牌");
			$offset = 8;
		} else {
			$this->writeLog("[$room_id] startShowRound前状态错误");
			return false;
		}

		$success = $this->setCircleTransaction($room_id,$pre_circle,$update_circle);
		if(!$success)
		{
			$this->logMessage('error', "function(startShowRound):并发忽略。room id:".$room_id." in file".__FILE__." on Line ".__LINE__);
			return false;
		}

		$player_status = array();
		//获取所有游戏用户
		$player_array = $this->queryPlayMember($room_id);
		foreach($player_array as $player_id)
		{
			//设置用户状态为未摊牌
			$this->updateAccountStatusNotNoty($room_id, $player_id, Game::AccountStatus_Notshow);
		}

		$cards = $this->queryCardInfo($room_id);

		for ($i=0; $i < 4; $i++) { 
			$card_info = array($cards[2*$i+$offset], $cards[2*$i+1+$offset]);
			$card_value = $this->caculateCardValue($card_info, $room_id);
			$card_array[] = array('card_info'=>$card_info, 'card_value'=>$card_value);
		}

		//设置自动摊牌定时器
		$this->setupShowPassiveTimer($room_id);

		$arr = array("result"=>0,"operation"=>"StartShow","data"=>$card_array,"result_message"=>"摊牌开始了","limit_time" => Game::LimitTime_Show);
		$this->pushMessageToGroup($room_id, $arr);

		return true;
	}


	/*
		结算，推送胜负结果
	*/
	protected function startWinRound($room_id)
	{
		$pre_circle = $this->queryCircle($room_id);
		if($pre_circle == Game::Circle_Show){
			$update_circle = Game::Circle_Pause;
			$this->writeLog("[$room_id] (上半场)摊牌完毕，即将中场休息");
		} else if($pre_circle == Game::Circle_Show2){
			$update_circle = -1;
			$this->writeLog("[$room_id] (下半场)摊牌完毕，一局完毕");
		} else {
			$this->writeLog("[$room_id] startWinRound 前状态错误");
			return false;
		}

		$success = $this->setCircleTransaction($room_id,$pre_circle,$update_circle);
		if(!$success)
		{
			$this->logMessage('error', "function(startWinRound):并发忽略。room id:".$room_id." in file".__FILE__." on Line ".__LINE__);
			return false;
		}

		//两两比分,固定庄家
		return $this->showWin($room_id);
	}


	//平衡积分
	protected function balanceScore($room_id, &$is_break){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);

		//获取庄家ID
		$banker_id = $this->queryBanker($room_id);
		$banker_score = 0;
		$banker_lose_score = 0;
		$banker_win_score = 0;

		$circle = $this->queryCircle($room_id);

		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$banker_seat_number = $Redis_Model->getZscore($RoomSequence_Key, $banker_id);
		$banker_seat_index = $banker_seat_number - 1;

		$cards =$this->queryCardInfo($room_id);
		$offset = ($circle == Game::Circle_Pause) ? 0 : 8;
		$banker_card = array($cards[2*$banker_seat_index+$offset], $cards[2*$banker_seat_index+1+$offset]);

		$players = $this->queryPlayMember($room_id);
		$player_balance = array($banker_id => 0);

		$winner_array = array();
		$loser_array = array();

		$bet_array = array();

		$banker_win_score = 0;

		$zrange_array['is_zrange'] = true;
		$zrange_array['key'] = $RoomSequence_Key;
		$zrange_array['start'] = 0;
		$zrange_array['stop'] = -1;
		$zrange_array['WITHSCORES'] = 1;
		$seat_number_array = $Redis_Model->zrangeSet($zrange_array);

		for ($i=0; $i < 4; $i++) { 
			if($banker_seat_number-1 == $i){
				continue;
			}
			//比牌
			$other_card =  array($cards[2*$i+$offset],  $cards[2*$i+1+$offset]);
			$card_value = $this->caculateCardValue($other_card, $room_id);
			$win_multiples = $this->compareCards($room_id, $banker_card, $other_card);

			$total =  $this->queryChip($room_id, $i, -1)['total'];
			$bet_array[] = array('index'=>$i, 'win_multiples'=>$win_multiples * $total);

			foreach ($players as $account_id) {
				if($account_id != $banker_id){
					$chip_info = $this->queryChip($room_id, $i, $account_id);
					$my_bet = $chip_info['my_bet'];
					$bet_time = $chip_info['bet_time'];
					
					if($my_bet > 0){
						$seat_number = $seat_number_array[$account_id];
						$score = $my_bet * $win_multiples;
						$info = array('account_id'=>$account_id, 'index'=>$i, 'my_bet'=>$my_bet,'bet_time'=>$bet_time, 'total'=>$total, 'card_value'=>$card_value, 'win_multiples'=>$win_multiples, 'seat_number'=>$seat_number, 'score'=>$score);
						
						if($win_multiples > 0){
							$winner_array[] = $info;
						} else {
							$loser_array[] = $info;
							$banker_win_score -= $score;
						}

						if(isset($player_balance[$account_id])){
							$player_balance[$account_id] += $score;
						} else {
							$player_balance[$account_id] = $score;
						}
						$player_balance[$banker_id]  -= $score;
					}
				}
			}
		}

		$room_rule = $this->queryRoomRule($room_id); 
		$banker_mode = $room_rule['banker_mode'];
		$banker_score_type   = $room_rule['banker_score_type'];

		$banker_pre_score = $this->queryAccountScore($room_id, $banker_id);
		if($banker_mode == Game::BankerMode_FreeGrab || $banker_score_type == 4 || $banker_pre_score + $player_balance[$banker_id] >= 0){
			foreach ($player_balance as $account_id => $score) {
				$Redis_Model->hincrbyField($RoomScore_Key, $account_id, $score);
			}
			if($banker_mode == Game::BankerMode_FixedBanker && $banker_pre_score + $player_balance[$banker_id] == 0 && $banker_score_type != 4 ){
				$is_break = 1;
			}
			return array('player_balance'=>$player_balance, 'bet_array'=>$bet_array,
			 'winner_array'=>$winner_array, 'loser_array'=>$loser_array) ;
		} 

		$is_break = 1;

		usort($winner_array, function($a, $b){
			if($a['card_value'] > $b['card_value']){
				return -1;
			} else if($a['card_value'] < $b['card_value']){
				return 1;
			} else {

				if($a['total'] > $b['total']){
					return -1;
				} else if($a['total'] < $b['total']){
					return 1;
				} else {
					if($a['my_bet'] > $b['my_bet']){
						return -1;
					} else if($a['my_bet'] < $b['my_bet']){
						return 1;
					} else {
						return ($a['bet_time'] > $b['bet_time']) ? 1 : -1;
					}
				}
			}
		});

		//需要强制结算
		$player_balance = array($banker_id => 0);
		$banker_capital_score = $banker_pre_score + $banker_win_score;

		foreach ($loser_array as $item) {
			$account_id = $item['account_id'];
			if(isset($player_balance[$account_id])){
				$player_balance[$account_id] += $item['score'];
			} else {
				$player_balance[$account_id] = $item['score'];
			}
		}

		foreach ($winner_array as $item) {
			$account_id = $item['account_id'];
			if($banker_capital_score - $item['score'] > 0)
			{
				if(isset($player_balance[$account_id])){
					$player_balance[$account_id] += $item['score'];
				} else {
					$player_balance[$account_id] = $item['score'];
				}

				$banker_capital_score -= $item['score'];
				
			}
			else
			{
				if(isset($player_balance[$account_id])){
					$player_balance[$account_id] += $banker_capital_score;
				} else {
					$player_balance[$account_id] = $banker_capital_score;
				}
				$banker_capital_score = 0;
				break;
			}
		}

		$player_balance[$banker_id]  -= $banker_pre_score;

		foreach ($player_balance as $account_id => $score) {
			$Redis_Model->hincrbyField($RoomScore_Key, $account_id, $score);
		}
		return array('player_balance'=>$player_balance, 'bet_array'=>$bet_array,
			'winner_array'=>$winner_array, 'loser_array'=>$loser_array) ;
	}

	/*
		结算，推送胜负结果
	*/
	protected function showWin($room_id)
	{
		//获取庄家ID
		$banker_id = $this->queryBanker($room_id);
		$banker_score = 0;
		$banker_lose_score = 0;
		$banker_win_score = 0;

		$circle = $this->queryCircle($room_id);

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);

		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);

		$is_break =0;
		$win_result = $this->balanceScore($room_id, $is_break);

		$player_balance = $win_result['player_balance'];
		$bet_array = $win_result['bet_array'];
		$winner_array = $win_result['winner_array'];
		$loser_array  = $win_result['loser_array'];

		$this->writeLog("[$room_id] win_result:".json_encode($win_result) );

		$total_num = $this->queryTotalNum($room_id);
		$game_num = $this->queryGameNumber($room_id);
		
		

		//获取积分榜
		$scoreboard = $Redis_Model->hgetallField($RoomScore_Key);
		$board_json_str = "";
		$ticket_checked_user = $this->queryTicketCheckedUser($room_id);

		foreach ($scoreboard as $key => $value) {
			if(!in_array($key, $ticket_checked_user)){
				//未扣房卡的用户不显示在积分榜上
				unset($scoreboard[$key]);
			}
		}

		$can_break = 0;	
		$banker_id = $this->queryBanker($room_id);
		$banker_limit = $this->queryBankerScore($room_id);

		$banker_score=$this->queryAccountScore($room_id, $banker_id);

		if($banker_limit > 0){
			$can_break = $banker_score >= 2 * $banker_limit;
		}
		

		$save_scoreboard = $scoreboard;

		$MMYSQL = $this->initMysql();
		//$balance_scoreboard = "-1";
		//保存积分榜
		if(is_array($scoreboard)){

			if($game_num >= $total_num)
			{
				
				foreach ($scoreboard as $account_id => $score) {

					if($banker_id==$account_id)
					{
						$score -= $banker_limit;
						$save_scoreboard[$account_id] = $score;

					}

					// $account_sql = 'select nickname from '.WX_Account.' where account_id ='.$account_id;
					// $name = $MMYSQL->single($account_sql);
					// $name_board[] = array('name'=>$name, 'score'=>$score, 'account_id'=>$account_id);
				}
				//$balance_scoreboard = array('time'=>time(), 'scoreboard'=>$name_board,'game_num'=>$game_num);
			}

			$board_json_str = json_encode($scoreboard);
		} else {
			$scoreboard = array();
			$board_json_str = "";
		}

		$mkv[Redis_Const::Room_Field_Scoreboard] = $board_json_str;
		$Redis_Model->hmsetField($Room_Key,$mkv);

		$msg_arr = array(
			'result' => 0,
			'operation' => 'Win',
			'result_message' => "获胜+积分榜",
			'data' => array(
				'player_balance' => $player_balance,
				'bet_array' => $bet_array,
				'score_board' => $scoreboard,
				'game_num' => $game_num,
				'total_num' =>  $total_num,
				//'balance_scoreboard' =>  $balance_scoreboard,

				'can_break' =>  $can_break,
				'is_break' => $is_break,
				'banker_id' => $banker_id,
				)
			);

		$this->pushMessageToGroup($room_id, $msg_arr);

		$this->writeLog("[$room_id] scoreboard:".json_encode($scoreboard) );

		//保存当前游戏结果
		$setting = $this->queryRoomSetting($room_id);
		$round = $setting[Redis_Const::Room_Field_GameRound];

		$game_info['room_id'] = $room_id;
		$game_info['game_type'] = Game::Game_Type;
		$game_info['dealer_num'] = Config::Dealer_Num;
		$game_info['round'] = $round;
		$game_info['game_num'] = $game_num;
		$game_info['total_num'] = $total_num;
		$game_info['banker_id'] = $banker_id;
		$game_info['half'] = $circle == Game::Circle_Pause ? 1 : 2;
		$game_info['extra'] = "";
		$this->saveGameResult($game_info, $winner_array, $loser_array, $player_balance);


		if($circle == Game::Circle_Pause){	//上半场
			$this->resetAllAccountStatus($room_id);  //重新设置所有用户状态为未准备
			$this->setupNextHalfPassiveTimer($room_id); //下半场开打定时器
		} else {	//下半场

			$this->updateRoomStatus($room_id, 1);   //房间状态，1等待、2进行中、3关闭


			// updatetime:2018-1-3 author:luoxiehua
			$banker_mode = $setting[Redis_CONST::Room_Field_BankerMode];
			if($banker_mode == Game::BankerMode_FreeGrab){
				$this->updateBanker($room_id,-1);
			}

			// end updatetime:2018-1-3 author:luoxiehua

			if($game_num >= $total_num){  //最后一局
				
				$round = $Redis_Model->hincrbyField($Room_Key, Redis_Const::Room_Field_GameRound, 1);
				$this->writeLog("[$room_id] 第".($round-1)."轮 结束!");
				
				$board_json_str = json_encode($save_scoreboard);



				$name_board = array();
				foreach ($save_scoreboard as $account_id => $score) {
					$account_sql = 'select nickname from '.WX_Account.' where account_id ='.$account_id;
					$name = $MMYSQL->single($account_sql);
					$name_board[] = array('name'=>$name, 'score'=>$score, 'account_id'=>$account_id);
					
				}

				$setting = $this->queryRoomSetting($room_id);
				$start_time = isset($setting[Redis_Const::Room_Field_StartTime])?$setting[Redis_Const::Room_Field_StartTime]:-1;


				//保存当局游戏结果

				$game_info['room_id'] = $room_id;
				$game_info['game_type'] = Game::Game_Type;
				$game_info['dealer_num'] = Config::Dealer_Num;
				$game_info['round'] = $round-1;
				$game_info['game_num'] = $game_num;
				$game_info['total_num'] = $total_num;
				$game_info['extra'] = "";

				//规则文本
				$rule_text = $this->formatRuleText($room_id);
				$balance_scoreboard = array('time'=>time(), 'scoreboard'=>$name_board,'game_num'=>$game_num);
				$balance_board_json_str = json_encode($balance_scoreboard['scoreboard']);
				//保存积分榜
				$board_array['start_time'] = $start_time;
				
				$board_array['create_time'] = time();
				$board_array['is_delete'] = G_CONST::IS_FALSE;
				$board_array['game_type'] = Game::Game_Type;  //游戏类型
				$board_array['room_id'] = $room_id;
				$board_array['round'] = $round-1;
				$board_array['game_num'] = $game_num;

				$board_array['rule_text'] = $rule_text;
				$board_array['board'] = $board_json_str;
				$board_array['balance_board'] = $balance_board_json_str;
				$board_id = $MMYSQL->insertReturnID(Room_Scoreboard,$board_array);

				//保存用户积分
				$game_info['score_board'] = $save_scoreboard;
				$this->saveAccountGameScore($game_info);

				
				//重置房间
				$this->initRoomData($room_id);
				return true;

			} else {

				$this->resetAllAccountStatus($room_id);  //重设所有用户状态为已
				
				$r_mkv[Redis_Const::Room_Field_ActiveUser] = -1;		//当前操作用户
				$r_mkv[Redis_Const::Room_Field_ActiveTimer] = -1;		//当前生效timer
				$r_mkv[Redis_Const::Room_Field_ReadyTime] = -1;		//房间倒计时
				$mset_result = $Redis_Model->hmsetField($Room_Key,$r_mkv);

				
				$Card_Key = strtr(Redis_Const::Card_Key, $replyArr);
				
				//删除每局玩家手牌hash
				$Redis_Model->deleteKey($Card_Key);
			}
		}

		//删除每局玩家筹码hash
		$Chip0_Key = strtr(Redis_Const::Chip0_Key, $replyArr);
		$Chip1_Key = strtr(Redis_Const::Chip1_Key, $replyArr);
		$Chip2_Key = strtr(Redis_Const::Chip2_Key, $replyArr);
		$Chip3_Key = strtr(Redis_Const::Chip3_Key, $replyArr);
		$Redis_Model->deleteKey($Chip0_Key);
		$Redis_Model->deleteKey($Chip1_Key);
		$Redis_Model->deleteKey($Chip2_Key);
		$Redis_Model->deleteKey($Chip3_Key);

		//重设每局游戏参数
		// $Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		// $Redis_Model->hmsetField($Play_Key,$parameter_ary);

		$this->writeLog("[$room_id]  $game_num/$total_num  is_break:".$is_break );

		if($is_break == 1)
		{
			if($game_num < $total_num)
			{
				$arrData['room_id'] = $room_id;
				// $arrData['winner_array'] = $winner_array;
				// $arrData['loser_array'] = $loser_array;
				// $arrData['type'] = 2;
				$this->breakRoom($arrData);
			}
		}

		return true;
	}


	protected function breakRoom($arrData)
	{
		$room_id = $arrData['room_id'];
	
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);

		//获取积分榜
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		$scoreboard = $Redis_Model->hgetallField($RoomScore_Key);

		$board_json_str = "";

		$ticket_checked_user = $this->queryTicketCheckedUser($room_id);

		//$player_array = $this->queryPlayMember($room_id);
		foreach ($scoreboard as $key => $value) {
			if(!in_array($key, $ticket_checked_user)){
				//未扣房卡的用户不显示在积分榜上
				unset($scoreboard[$key]);
			}
		}
		$save_scoreboard = $scoreboard;

		$total_num = $this->queryTotalNum($room_id);
		$game_num = $this->queryGameNumber($room_id);

		$MMYSQL = $this->initMysql();

		$banker_id = $this->queryBanker($room_id);
		$banker_score = $this->queryBankerScore($room_id);

		foreach ($scoreboard as $account_id => $score) {
			$account_sql = 'select nickname from '.WX_Account.' where account_id ='.$account_id;
			$name = $MMYSQL->single($account_sql);
			if($banker_id == $account_id)
			{
				$score -= $banker_score;
				$save_scoreboard[$account_id] = $score;
			}
		}

		
		$msg_arr = array(
			'result' => 0,
			'operation' => 'BreakRoom',
			'result_message' => "解散房间",
			'data' => array(
				'score_board' => $scoreboard,
				'game_num' => $game_num,
				'total_num' =>  $total_num,
				//'balance_scoreboard' =>  $balance_scoreboard,
				)
			);

		$this->pushMessageToGroup($room_id, $msg_arr);

		$this->writeLog("[$room_id] 解散房间 scoreboard:".json_encode($scoreboard) );

		$round = $Redis_Model->hincrbyField($Room_Key, Redis_Const::Room_Field_GameRound, 1);
		$this->writeLog("[$room_id] 第".($round-1)."轮 结束!");

		$game_info['room_id'] = $room_id;
		$game_info['game_type'] = Game::Game_Type;
		$game_info['dealer_num'] = Config::Dealer_Num;
		$game_info['round'] = $round-1;
		
		$board_json_str = json_encode($save_scoreboard);
		//保存积分榜

		$name_board = array();
		foreach ($save_scoreboard as $account_id => $score) {
			$account_sql = 'select nickname from '.WX_Account.' where account_id ='.$account_id;
			$name = $MMYSQL->single($account_sql);
			$name_board[] = array('name'=>$name, 'score'=>$score, 'account_id'=>$account_id);
			
		}

		$setting = $this->queryRoomSetting($room_id);
		$start_time = isset($setting[Redis_Const::Room_Field_StartTime])?$setting[Redis_Const::Room_Field_StartTime]:-1;

		//规则文本
		$rule_text = $this->formatRuleText($room_id);
		$balance_scoreboard = array('time'=>time(), 'scoreboard'=>$name_board,'game_num'=>$game_num);
		$balance_board_json_str = json_encode($balance_scoreboard['scoreboard']);

		$board_array['start_time'] = $start_time;
		$board_array['create_time'] = time();
		$board_array['is_delete'] = G_CONST::IS_FALSE;
		$board_array['game_type'] = Game::Game_Type;
		$board_array['room_id'] = $room_id;
		$board_array['round'] = $round-1;
		$board_array['game_num'] = $game_num;

		$board_array['rule_text'] = $rule_text;
		$board_array['board'] = $board_json_str;
		$board_array['balance_board'] = $balance_board_json_str;
		$board_id = $MMYSQL->insertReturnID(Room_Scoreboard,$board_array);
		
		//保存用户积分
		$game_info['score_board'] = $save_scoreboard;
		$this->saveAccountGameScore($game_info);
		
		//重置房间
		$this->initRoomData($room_id);
		return true;
	}


	
	//重新设置所有用户状态为未准备
	protected function resetAllAccountStatus($room_id, $reset_status=Game::AccountStatus_Notready){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);

		$mkv = array();
		$members = $this->queryRoomMembers($room_id);
		if(is_array($members) && count($members)){
			foreach ($members as $account_id) {
				$pre_status = $this->queryAccountStatus($room_id, $account_id);
				$status = ($pre_status == Game::AccountStatus_Initial) ? Game::AccountStatus_Initial : $reset_status;
				if($status != Game::AccountStatus_Initial)
				{
					$is_online = $this->queryOnlineStatus($room_id, $account_id);
					if($is_online == 0)
					{
						$status = Game::AccountStatus_Notready;
					}
				}
				$mkv[$account_id] = $status;
			}
		}
		if(count($mkv) > 0)
		{
			$mset_result = $Redis_Model->hmsetField($AccountStatus_Key,$mkv);  //用户状态
		}
	}

	//重新设置所有用户分数为0
	protected function resetAllAccountScore($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);

		$mkv = array();
		$members = $this->queryRoomMembers($room_id);
		if(is_array($members) && count($members)){
			foreach ($members as $account_id) {
				$mkv[$account_id] = 0;
			}
		}
		if(count($mkv) > 0)
		{
			$mset_result = $Redis_Model->hmsetField($RoomScore_Key,$mkv);  //用户状态
		}
	}

	//广播用户状态改变
	protected function notyUpdateAccountStatusToGroup($room_id, $noty_arr, $exclude_client_id=null){

		if(!isset($noty_arr['account_id']) || !isset($noty_arr['account_status']) ){
			$this->writeLog("function(notyUpdateAccountStatusToGroup):lack of params"." in file".__FILE__." on Line ".__LINE__);
			return false;
		}

		$msg_arr = array("result"=>"0","operation"=>"UpdateAccountStatus","data"=>$noty_arr,"result_message"=>"用户状态改变");
		$this->pushMessageToGroup($room_id, $msg_arr, $exclude_client_id=null);
	}

	/*
		比牌
	*/
	protected function compareCards($room_id,$banker_card,$other_card)
	{
		$banker_value = $this->caculateCardValue($banker_card, $room_id);
		$other_value = $this->caculateCardValue($other_card, $room_id);
		if($other_value > $banker_value){	//闲家赢
			$multiples = substr($other_value, 0, 1);
		} else {	//庄家赢
			$multiples = 0 - substr($banker_value, 0, 1);
		}
		return $multiples;
	}

	protected function caculateCardValue($cards, $room_id)
	{
		if(count($cards)!=2){
			$this->writeLog("cards count error"." in file".__FILE__." on Line ".__LINE__);
			return 0;
		}

		rsort($cards, SORT_NUMERIC);  //大到小排序

		if($cards[0] == 5 && $cards[1] == 5 ){
			$value = '40000';
		} else if($cards[0] == $cards[1]) {
			$value = '3' . $cards[0] . '00';
		} else {
			$combo_point = ($cards[0] + $cards[1]) % 100;
			if($combo_point >= 80){
				$value = '2' . $combo_point . $cards[0];
			} else {
				if($combo_point==0){
					$combo_point = "00";
				}
				$value = '1' . $combo_point . $cards[0];
			}
		}
		$room_rule = $this->queryRoomRule($room_id);
		$rule_type = $room_rule['rule_type'];

		if($cards[0] == 80 && $cards[1] == 20) {
			if($rule_type == 2){
				$value = 29900;
			} else if($rule_type == 3){
				$value = 30000;
			}
		}

		return $value;
	}

	//发牌 全随机规则
	protected function dealCard($room_id){
		$player_cards = array();
		$Card = array("10","20","30","40","50","60","70","80","90","5",
					  "10","20","30","40","50","60","70","80","90","5"
				);
        mt_srand();
		shuffle($Card);

//		 $Card = array("40","50","20","30","70","70","90","20",
//             "50","40", "90","20","40","20","30","30","70","70","5","5"
//		 		);
		
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Card_Key = strtr(Redis_Const::Card_Key, $replyArr);
		$card_str = implode(",", $Card);
		$mkv = array($Card_Key => $card_str);
		$Redis_Model->msetStringValue($mkv);



		return $Card;
	}

	protected function queryCardInfo($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Card_Key = strtr(Redis_Const::Card_Key, $replyArr);
		$card_str = $Redis_Model->getStringValue($Card_Key);
		$cards = explode(",", $card_str);
		return $cards;
	}

	
	/***********************************
			timer_function
	***********************************/


	//设置 自动开局 定时器
	protected function setupStartGamePassiveTimer($room_id,$is_pushTimer=false){

		$this->updateReadyTime($room_id, time());
		$limit_time = $this->queryGameNumber($room_id) > 0 ? Game::LimitTime_Ready : Game::LimitTime_StartGame;

		$callback_array = array(
			'operation' => "StartGamePassive",
			'room_id' => $room_id,
			'data' => array(
				)
			);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => $limit_time,
				'callback_array' => $callback_array
				)

			);
		$this->sendToTimerServer($arr);

		if($is_pushTimer)
		{
			$arr = array("result"=>0,"operation"=>"StartLimitTime","data"=>array('limit_time' => $limit_time),"result_message"=>"开始倒计时");
			$this->pushMessageToGroup($room_id, $arr);
		}
	}

	//设置 自动不叫庄 定时器
	protected function setupGrabPassiveTimer($room_id)
	{
		$room_rule = $this->queryRoomRule($room_id); 
		$banker_mode = $room_rule['banker_mode'];
		$game_num = $this->queryGameNumber($room_id);
		if($banker_mode == Game::BankerMode_FreeGrab || $game_num == 1) {
			$this->updateReadyTime($room_id, time());
			$callback_array = array(
				'operation' => "GrabPassive",
				'room_id' => $room_id,
				'data' => array(
					)
				);
			$arr = array(
				'operation' => "BuildTimer",
				'room_id'   => $room_id,
				'data' => array(
					'limit_time' => Game::LimitTime_Grab,
					'callback_array' => $callback_array
					)
				);
			$this->sendToTimerServer($arr);
		} else {
			//抢庄结束设置
			$this->grabPassiveOpt($room_id);
		}
	}

	//设置 自动洗牌 定时器
	protected function setupShufflePassiveTimer($room_id, $limit_time, $is_only)
	{
		$add = $is_only ? 1 : 3;
		$limit_time += $add;
		if($limit_time > 0)
		{
			$this->updateReadyTime($room_id, time());
			$callback_array = array(
				'operation' => "ShufflePassive",
				'room_id' => $room_id,
				'data' => array(
					)
				);
			$arr = array(
				'operation' => "BuildTimer",
				'room_id'   => $room_id,
				'data' => array(
					'limit_time' => $limit_time,
					'callback_array' => $callback_array
					)
				);
			$this->sendToTimerServer($arr);
		} else {
			//洗牌结束设置
			$this->startBetRound($room_id);
		}
	}

	//设置 自动下注 定时器
	protected function setupBetPassiveTimer($room_id)
	{
		$this->updateReadyTime($room_id, time());
		$callback_array = array(
			'operation' => "BetPassive",
			'room_id' => $room_id,
			'data' => array(
				)
			);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => Game::LimitTime_Betting + 1, 
				'callback_array' => $callback_array
				)
			);
		$this->sendToTimerServer($arr);
	}

	//设置 自动发牌 定时器
	protected function setupDealPassiveTimer($room_id)
	{
		$this->updateReadyTime($room_id, time());
		$callback_array = array(
			'operation' => "DealPassive",
			'room_id' => $room_id,
			'data' => array(
				)
			);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => Game::LimitTime_Deal ,
				'callback_array' => $callback_array
				)
			);
		$this->sendToTimerServer($arr);
	}

	//设置 自动摊牌 定时器
	protected function setupShowPassiveTimer($room_id){

		$this->updateReadyTime($room_id, time());
		$callback_array = array(
			'operation' => "ShowPassive",
			'room_id' => $room_id,
			'data' => array(
				)
			);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => Game::LimitTime_Show + 6,
				'callback_array' => $callback_array
				)
			);
		$this->sendToTimerServer($arr);
	}

	//设置 下半场开打 定时器
	protected function setupNextHalfPassiveTimer($room_id){

		$this->updateReadyTime($room_id, time());
		$callback_array = array(
			'operation' => "NextHalfPassive",
			'room_id' => $room_id,
			'data' => array(
				)
			);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => Game::LimitTime_Pause,
				'callback_array' => $callback_array
				)
			);
		$this->sendToTimerServer($arr);
	}


	//设置 清理房间 定时器
	protected function setupClearRoomPassiveTimer($room_id){

		$callback_array = array(
			'operation' => "ClearRoomPassive",
			'room_id' => $room_id,
			'data' => array(
				)
			);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => Game::LimitTime_ClearRoom,
				'callback_array' => $callback_array
				)
			);
		$this->sendToTimerServer($arr);
		$this->updateReadyTime($room_id, -1);
		$this->writeLog("[$room_id] 设置了自动清理房间定时器");
	}

	//显示房间准备倒计时的数值
	protected function showRoomCountdown($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$ready_time = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_ReadyTime);
		if($ready_time > 0){

			$circle = $this->queryCircle($room_id);

			if($circle == Game::Circle_Grab)
			{
				$limit_time = Game::LimitTime_Grab;
			}
			if($circle == Game::Circle_Shuffle)
			{
				$limit_time = Game::LimitTime_Shuffle + 2;
			}
			else if($circle == Game::Circle_Bet || $circle == Game::Circle_Bet2)
			{
				$limit_time = Game::LimitTime_Betting + 1;
			}
			else if($circle == Game::Circle_Deal || $circle == Game::Circle_Deal2)
			{
				$limit_time = Game::LimitTime_Deal;
			}
			else if($circle == Game::Circle_Show || $circle == Game::Circle_Show2)
			{
				$limit_time = Game::LimitTime_Show + 6;
			}
			else
			{
				$limit_time = $this->queryGameNumber($room_id) > 0 ? Game::LimitTime_Ready : Game::LimitTime_StartGame;
			}
			
			$countdown = $limit_time - time() + $ready_time;

			if($countdown > 0){
				$arr = array("result"=>0,"operation"=>"StartLimitTime","data"=>array('limit_time' => $countdown),"result_message"=>"开始倒计时");
				$this->pushMessageToCurrentClient($arr);
			}
		} 
		return;
	}


	//取消定时器
	protected function deleteRoomTimer($room_id){

		$timer_id = $this->queryRoomTimerId($room_id);
		if($timer_id > 0){
			$arr = array(
				'operation' => "DeleteTimer",
				'room_id'   => $room_id,
				'data' => array(
					'timer_id' => $timer_id
					)

				);
			$this->sendToTimerServer($arr);
		}
		$this->updateRoomTimerId($room_id, -1);
		$this->updateReadyTime($room_id, -1);
	}

	/*
		推给定时器服务器
	*/
	public function sendToTimerServer($msg_array = "")
	{
		$message = $this->_JSON($msg_array);

		$socket_name = "Timer";
		$Socket_Model = Socket_Model::getModelObject($socket_name);
		$Socket_Model->sendMessageToSocket($socket_name,$message);

		return true;
	}


	/***********************************
			database_function
	***********************************/
	//保存开始准备时间
	protected function updateReadyTime($room_id, $ready_time){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$mkv[Redis_Const::Room_Field_ReadyTime] = $ready_time;	//开始倒计时的时间点
		$mset_result = $Redis_Model->hmsetField($Room_Key,$mkv);
	}


	//保存定时器id
	protected function updateRoomTimerId($room_id, $timer_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$mkv[Redis_Const::Room_Field_ActiveTimer] = $timer_id;
		$mset_result = $Redis_Model->hmsetField($Room_Key,$mkv);
	}
	//获取定时器id
	protected function queryRoomTimerId($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_ActiveTimer);
		return $result;
	}
	//获取房主id
	protected function queryCreator($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_Creator);
		return $result;
	}
	//更新房间状态
	protected function updateRoomStatus($room_id, $status){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$mkv[Redis_Const::Room_Field_Status] = $status;
		$mset_result = $Redis_Model->hmsetField($Room_Key,$mkv);
	}

	//获取房间用户有序集合
	protected function queryRoomMembers($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$zrange_array['is_zrange'] = true;
		$zrange_array['key'] = $RoomSequence_Key;
		$zrange_array['start'] = 0;
		$zrange_array['stop'] = -1;
		$members = $Redis_Model->zrangeSet($zrange_array);
		if(is_array($members) ){
			return $members;
		} else {
			return array();
		}
	}

	//获取房间每轮需要消耗的房卡数
	protected function queryTicketCount($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_TicketCount);
		return $result > 0 ? $result : 1;
	}

	//获取下注
	protected function queryChip($room_id, $position_index, $account_id=-1){
		$Redis_Model = Redis_Model::getModelObject();
		
		$result = $Redis_Model->hgetallField("Chip".$position_index.":".$room_id);

		$total = 0;
		$my_bet = 0;
		$bet_time = 0;

		if($result){
			foreach ($result as $acc_id => $value) {
				if(is_int($acc_id)){
					$total += $value;
				}

				if($account_id == $acc_id){
					$my_bet = $value;
				} else if( 't_'.$account_id == $acc_id){
					$bet_time = $value;
				}
			}
		}
		return array('my_bet'=>$my_bet, 'total'=>$total, 'bet_time'=>$bet_time);
	}

	//获取房间数据
	protected function queryRoomData($room_id){



		if(!isset($result['creator']))
		{
			$result['creator'] = "-1";
		}
		if(!isset($result['scoreboard']))
		{
			$result['scoreboard'] = "";
		}


		return $result;
	}


	//获取房间规则
	protected function queryRoomRule($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$result = $Redis_Model->hgetallField($Room_Key);

		$ticket_count = isset($result[Redis_CONST::Room_Field_TicketCount]) ? $result[Redis_CONST::Room_Field_TicketCount] : Game::Default_SpendTicketCount;
		$banker_score = isset($result[Redis_CONST::Room_Field_BankerScore]) ? $result[Redis_CONST::Room_Field_BankerScore] : Config::BankerScore_1;
		
		$rule_ary['ticket_count'] = $ticket_count;
		switch ($banker_score ) {
			case Config::BankerScore_1:
				$rule_ary['banker_score_type'] = 1;
				break;
			case Config::BankerScore_2:
				$rule_ary['banker_score_type'] = 2;
				break;
			case Config::BankerScore_3:
				$rule_ary['banker_score_type'] = 3;
				break;
			case Config::BankerScore_4:
				$rule_ary['banker_score_type'] = 4;
				break;
			
			default:
				$rule_ary['banker_score_type'] = -1;
				break;
		}

		$rule_ary['banker_mode'] = isset($result[Redis_CONST::Room_Field_BankerMode]) ? $result[Redis_CONST::Room_Field_BankerMode] : Game::BankerMode_FreeGrab;

		$rule_ary['rule_type'] = isset($result[Redis_CONST::Room_Field_RuleType]) ? $result[Redis_CONST::Room_Field_RuleType] : 1;

		$rule_ary['chip_type'] = isset($result[Redis_CONST::Room_Field_ChipType]) ? $result[Redis_CONST::Room_Field_ChipType] : 1;

		return $rule_ary;
	}

	//整理规则内容文本
	protected function formatRuleText($room_id,$room_data="")
	{
		$rule_text = "";
		$setting = $this->queryRoomSetting($room_id);
		$ticket_count=isset($setting[Redis_Const::Room_Field_TicketCount]) ?$setting[Redis_Const::Room_Field_TicketCount]:1;
		$chip_type= isset($setting[Redis_Const::Room_Field_ChipType])?$setting[Redis_Const::Room_Field_ChipType]:1;
		$banker_mode= isset($setting[Redis_Const::Room_Field_BankerMode])?$setting[Redis_Const::Room_Field_BankerMode]:1;
		$rule_type= isset($setting[Redis_Const::Room_Field_RuleType])?$setting[Redis_Const::Room_Field_RuleType]:1;
		$banker_score   =isset($setting[Redis_Const::Room_Field_BankerScore]) ?$setting[Redis_Const::Room_Field_BankerScore]:300;

		//局数房卡规则
		$ticket_type_text = (Config::GameNum_EachRound * $ticket_count)."局/".$ticket_count."张房卡";
		$rule_text .= $ticket_type_text;

		//游戏类型
		$rule_text .= ",";
		if($banker_mode ==  Game::BankerMode_FreeGrab){
			$rule_text .= "自由抢庄";

			//筹码类型
			$rule_text .= ",";
			switch($chip_type)
			{
				case 1:
					$rule_text .= "筹码:4,7,10";
					break;
				case 2:
					$rule_text .= "筹码:10,20,30";
					break;
				case 3:
					$rule_text .= "筹码:20,30,50";
					break;
				default:
			}

		} else {
			$rule_text .= "固定庄家";
			$rule_text .= ",上限:".$banker_score."分";
		}

		//二八杠选项
		$rule_text .= ",";
		switch($rule_type)
		{
			case 1:
				$rule_text .= "无二八杠";
				break;
			case 2:
				$rule_text .= "二八杠2倍";
				break;
			case 3:
				$rule_text .= "二八杠3倍";
				break;
			default:
		}

		return $rule_text;
	}


	/*
		保存游戏结果
	*/
	protected function saveGameResult($game_info, $winner_array, $loser_array, $player_balance)
	{
		$timestamp = time();
		$MMYSQL = $this->initMysql();
		$room_id = $game_info['room_id'];
		$game_type = $game_info['game_type'];

		$game_data['time'] = $timestamp;
		$game_data['rid'] = $game_info['room_id'];
		$game_data['rnd'] = $game_info['round'];
		$game_data['gnum'] = $game_info['game_num'];
		$game_data['tnum'] = $game_info['total_num'];
		$game_data['bid'] = $game_info['banker_id'];
		$game_data['half'] = $game_info['half'];
		//$game_data['extra'] = $game_info['extra'];

		//获取所有人手牌
		// $Redis_Model = Redis_Model::getModelObject();
		// $replyArr = array("[roomid]"=>$room_id);
		// $Card_Key = strtr(Redis_Const::Card_Key, $replyArr);
		// $card_array = $Redis_Model->getStringValue($Card_Key);

		//获取所有人倍数
		//$playing_array = array();	//游戏中玩家
		$player_array = array();	//玩家当局数据

		foreach($winner_array as $winner_item)
		{
			$player_id = $winner_item['account_id'];
			$array['p'] = $player_id;
			$array['i'] = $winner_item['index'];
			//$array['s'] = $loser_item['score'];
			//$array['c'] = $card_array[$player_id];
			$array['cv'] = $winner_item['card_value'];

			$array['mb'] = $winner_item['my_bet'];
			$array['bt'] = $winner_item['bet_time'];
			$array['t']  = $winner_item['total'];
			
			$player_array[] = $array;
			unset($array);
		}
		foreach($loser_array as $loser_item)
		{
			$player_id = $loser_item['account_id'];
			$array['p'] = $player_id;
			$array['i'] = $loser_item['index'];
			//$array['s'] = $loser_item['score'];
			//$array['c'] = $card_array[$player_id];
			$array['cv'] = $loser_item['card_value'];

			$array['mb'] = $loser_item['my_bet'];
			$array['bt'] = $loser_item['bet_time'];
			$array['t']  = $loser_item['total'];

			$player_array[] = $array;
			unset($array);
		}

		foreach ($player_array as $key=>$player_item) {
			$player_id = $player_item['p'];
			//获取用户当前名字
			$account_sql = 'select nickname from '.WX_Account.' where account_id ='.$player_id;
			$name = $MMYSQL->single($account_sql);
			$player_array[$key]['n'] = $name;
		}

		$card_array = array();
		$offset = $game_data['half'] == 2 ? 8 : 0;
		$cards = $this->queryCardInfo($room_id);
		for ($i=0; $i < 4; $i++) { 
			$card_info = array($cards[2*$i+$offset], $cards[2*$i+1+$offset]);
			$card_value = $this->caculateCardValue($card_info, $room_id);
			$card_array[] = array('c'=>$card_info, 'cv'=>$card_value);
		}

		$game_result['pAry'] = $player_array;
		$game_result['gData'] = $game_data;
		$game_result['bData'] = $player_balance;
		$game_result['cAry'] = $card_array;
		$game_result_json = json_encode($game_result);

		$array['create_time'] = $timestamp;
		$array['game_type'] = $game_type;
		$array['room_id'] = $room_id;
		$array['round'] = $game_data['rnd'];
		$array['game_result'] = $game_result_json;

		$result_id = $MMYSQL->insertReturnID(Room_GameResult,$array);
		unset($array);

		return true;
	}


	protected function saveAccountGameScore($game_info)
	{
		if(Config::Is_SendGameScore == 0){
			return ;
		}
		$game_type = $game_info['game_type'];
		$dealer_num = $game_info['dealer_num'];

		$game_result['time'] = time();
		$game_result['rid'] = $game_info['room_id'];
		$game_result['rnd'] = $game_info['round'];
		$game_result['board'] = $game_info['score_board'];
		
		$game_result_str = json_encode($game_result);
		$push_array = array($game_result_str);

		//连接日志系统
		$Redis_Model = Redis_Model::getModelObjectLogs();
		$replyArr = array("[dealernum]"=>$dealer_num,"[gametype]"=>$game_type);

		$GameScore_Key = strtr(Redis_Const::GameScore_Key, $replyArr);
		$push_result = $Redis_Model->pushListLogs($is_rpush=0,$is_pushx=0,$GameScore_Key,$push_array); //lpush


		//推送到结果处理器
		$msg_array = array(
				'operation' => "PullGameScore",
				'dealer_num'   => $dealer_num,
				'game_type'   => $game_type,
				'data' => array(
					)
				);
		$this->sendToGameResultProcessor($msg_array);

		return true;
	}

	/*
		推推送给游戏结果处理器
	*/
	public function sendToGameResultProcessor($msg_array="")
	{
		$message = $this->_JSON($msg_array);

		$socket_name = "Processor";
		$Socket_Model = Socket_Model::getModelObject($socket_name);
		$Socket_Model->sendMessageToSocket($socket_name,$message);

		return true;
	}


	//获取房间一轮总局数
	protected function queryTotalNum($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_TotalNum);
		return $result;
	}
	//获取房间状态
	protected function queryRoomStatus($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_Status);
		if($result === false)
		{
			$this->initRoomData($room_id);
			$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_Status);
		}
		return $result;
	}


	//重置房间信息
	protected function initRoomData($room_id)
	{
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);

		//关闭房间
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
        $newRoomNumber = $Redis_Model->hgetField($Room_Key,Redis_CONST::Room_Field_NewNumber);
		
		//$SeenCard_Key = strtr(Redis_Const::SeenCard_Key, $replyArr);
		$Card_Key = strtr(Redis_Const::Card_Key, $replyArr);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);

		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		$TicketChecked_Key = strtr(Redis_Const::TicketChecked_Key, $replyArr);

		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$Grab_Key = strtr(Redis_Const::Grab_Key, $replyArr);
		
		$Room_mkv[Redis_Const::Room_Field_GameNum] = 0;			//游戏局数
		$Room_mkv[Redis_Const::Room_Field_Status] = 1;// Game::RoomStatus_Closed;	//房间状态，1等待、2进行中、3未激活
		$Room_mkv[Redis_Const::Room_Field_DefaultScore] = Game::Default_Score;		//开局默认分数
		$Room_mkv[Redis_Const::Room_Field_Scoreboard] = "";		//积分榜清零
		$Room_mkv[Redis_Const::Room_Field_Creator] = -1;		//创建者清空

		$Room_mkv[Redis_Const::Room_Field_ActiveUser] = -1;		//当前操作用户
		$Room_mkv[Redis_Const::Room_Field_ActiveTimer] = -1;		//当前生效timer
		$Room_mkv[Redis_Const::Room_Field_ReadyTime] = -1;		//房间倒计时
		$Room_mkv[Redis_Const::Room_Field_StartTime] = -1;

		$mset_result = $Redis_Model->hmsetField($Room_Key,$Room_mkv);

		//删除每局玩家筹码hash
		$Chip0_Key = strtr(Redis_Const::Chip0_Key, $replyArr);
		$Chip1_Key = strtr(Redis_Const::Chip1_Key, $replyArr);
		$Chip2_Key = strtr(Redis_Const::Chip2_Key, $replyArr);
		$Chip3_Key = strtr(Redis_Const::Chip3_Key, $replyArr);
		$Redis_Model->deleteKey($Chip0_Key);
		$Redis_Model->deleteKey($Chip1_Key);
		$Redis_Model->deleteKey($Chip2_Key);
		$Redis_Model->deleteKey($Chip3_Key);
		//删除每局玩家看牌标识hash
		//$Redis_Model->deleteKey($SeenCard_Key);
		//删除每局玩家手牌hash
		$Redis_Model->deleteKey($Card_Key);
		//删除每局游戏参数
		$Redis_Model->deleteKey($Play_Key);
		//删除用户状态hash
		$Redis_Model->deleteKey($AccountStatus_Key);
		//删除用户状态hash
		$Redis_Model->deleteKey($RoomScore_Key);
		$Redis_Model->deleteKey($TicketChecked_Key);
		$Redis_Model->deleteKey($RoomSequence_Key);
		$Redis_Model->deleteKey($Grab_Key);
        $RedisLog_Model = Redis_Model::getModelObjectLogs();
        $RedisLog_Model->hdelFiled(Redis_CONST::Room_New_Key,$newRoomNumber);
		if(Config::Room_IsReuse == 0)
		{
			$MMYSQL = $this->initMysql();
			//房间设置成已关闭
			$MMYSQL->update(Room)->set("is_close", "1")->where("room_id=".$room_id)->query();

			$Redis_Model->deleteKey($Room_Key);
		}

		return true;
	}

	//获取房间当前局数
	protected function queryGameNumber($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_GameNum);
		return $result;
	}

	//自增长房间当前局数、轮数
	protected function updateGameNumberRound($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$gnum = $Redis_Model->hincrbyField($Room_Key, Redis_Const::Room_Field_GameNum, 1);

		$this->writeLog("[$room_id] 新的一局 :".$gnum);

		if($gnum == 1){
			//设置开局时间
			$mkv[Redis_Const::Room_Field_StartTime] = time();
			$Redis_Model->hmsetField($Room_Key,$mkv);
		}

		return $gnum;
	}

	//更新用户状态
	protected function updateAccountStatus($room_id, $account_id, $status,$multiples=""){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
		
		$mkv[$account_id] = $status;
		$mset_result = $Redis_Model->hmsetField($AccountStatus_Key,$mkv);

		//广播用户状态改变
		$noty_arr = array(
			'account_id' => $account_id,
			'account_status'=>$status,
			'online_status'=>$this->queryOnlineStatus($room_id, $account_id),
			'banker_multiples'=>$multiples
			);

		$this->writeLog("[$room_id] ($account_id) 状态改变 ". $status);
		$this->notyUpdateAccountStatusToGroup($room_id, $noty_arr);
	}


	//更新用户状态,不通知
	protected function updateAccountStatusNotNoty($room_id, $account_id, $status){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
		
		$mkv[$account_id] = $status;
		$mset_result = $Redis_Model->hmsetField($AccountStatus_Key,$mkv);
		return true;
	}


	//获取在线状态
	protected function queryOnlineStatus($room_id, $account_id){

		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);
		$room_aid = strtr(Game::RoomUser_UID, $replyArr);

		$is_online = Gateway::isUidOnline($room_aid);
		return $is_online > 0 ? 1 : 0;
	}

	//获取准备人数
	protected function queryReadyCount($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
		
		$result = $Redis_Model->hgetallField($AccountStatus_Key);
		$count = 0;
		if(Redis_CONST::DATA_NONEXISTENT !== $result){
			foreach ($result as $account_id => $status) {
				if($status == Game::AccountStatus_Ready){
					$count++;
				}
			}
		}
		return $count;
	}

	//获取准备的人
	protected function queryReadyUser($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
		
		$ready_user_array = [];
		$result = $Redis_Model->hgetallField($AccountStatus_Key);
		if(Redis_CONST::DATA_NONEXISTENT !== $result){
			foreach ($result as $account_id => $status) {
				if($status == Game::AccountStatus_Ready){
					$ready_user_array[] = $account_id;
				}
			}
		}
		return $ready_user_array;
	}

	//获取在桌的人
	protected function queryTableUser($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
	
		//获取在桌上的人
		$at_table_user = array();
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$zrange_array['is_zrange'] = true;
		$zrange_array['key'] = $RoomSequence_Key;
		$zrange_array['start'] = 0;
		$zrange_array['stop'] = -1;
		$zrange_array['WITHSCORES'] = 1;
		$members = $Redis_Model->zrangeSet($zrange_array);
		if(is_array($members) ){

			foreach ($members as $account_id => $seat_number) {
				if($seat_number > 4 || $this->queryOnlineStatus($room_id, $account_id) == 0){
					unset($members[$account_id]);
				}
			}

			if(isset($members) && is_array($members)){
				$at_table_user = array_keys($members);
			}
		}
		return $at_table_user;
	}

	//获取扣除了房卡的人
	protected function queryTicketCheckedUser($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$TicketChecked_Key = strtr(Redis_Const::TicketChecked_Key, $replyArr);
		
		$user_array = [];
		$result = $Redis_Model->hgetallField($TicketChecked_Key);
		if(Redis_CONST::DATA_NONEXISTENT !== $result){
			foreach ($result as $account_id => $status) {
				if($status >= 1){
					$user_array[] = $account_id;
				}
			}
		}
		return $user_array;
	}

	//获取用户状态
	protected function queryAccountStatus($room_id, $account_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($AccountStatus_Key,$account_id);
		return $result;
	}

	//获取用户是否已经摊牌
	protected function queryShowCard($room_id, $account_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$ShowCard_Key = strtr(Redis_Const::ShowCard_Key, $replyArr);
		$result = $Redis_Model->hgetField($ShowCard_Key,$account_id);
		return $result == 1 ? 1 : 0;
	}

	//获取用户是否已经扣除房卡
	protected function queryTicketChecked($room_id, $account_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$TicketChecked_Key = strtr(Redis_Const::TicketChecked_Key, $replyArr);
		$result = $Redis_Model->hgetField($TicketChecked_Key,$account_id);
		return $result >= 1 ? 1 : 0;
	}

	//获取用户积分
	protected function queryAccountScore($room_id, $account_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($RoomScore_Key,$account_id);
		return $result;
	}

	//设置用户积分
	protected function updateAccountScore($room_id, $account_id,$score)
	{
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		
		$parameter_ary[$account_id] = $score;
		$mset_result = $Redis_Model->hmsetField($RoomScore_Key,$parameter_ary);
		return true;
	}

	//返回积分榜
	protected function queryScoreboard($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_Scoreboard);
		if($result !== Redis_Const::DATA_NONEXISTENT){
			$arr = json_decode($result);
		} else {
			$arr = new stdClass();
		}
		return $arr;
	}

	//获取房间状态
	protected function queryRoomScoreboard($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_Scoreboard);
		return $result;
	}


	//获取叫分基准
	protected function queryBenchmark($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$result = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_Benchmark);
		return $result;
	}
	//设置叫分基准
	protected function updateBenchmark($room_id, $benchmark){
		if($benchmark < 0){
			return false;
		}

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		
		$mkv[Redis_Const::Play_Field_Benchmark] = $benchmark;
		$mset_result = $Redis_Model->hmsetField($Play_Key,$mkv);
	}

	//获取底分
	protected function queryBaseScore($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_BaseScore);
		return $result;
	}
	//设置底分
	protected function updateBaseScore($room_id, $score){
		if($score < 0){
			return false;
		}
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$mkv[Redis_Const::Room_Field_BaseScore] = $score;
		$mset_result = $Redis_Model->hmsetField($Room_Key,$mkv);
	}


	//获取庄家account_id
	protected function queryBanker($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$result = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_Banker);
		return $result;
	}
	//设置庄家account_id
	protected function updateBanker($room_id,$account_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		
		$parameter_ary[Redis_CONST::Play_Field_Banker] = $account_id;
		$mset_result = $Redis_Model->hmsetField($Play_Key,$parameter_ary);
		return true;
	}
	//获取回合
	protected function queryCircle($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$result = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_Circle);
		return $result;
	}
	//设置回合
	protected function updateCircle($room_id,$circle){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		
		$parameter_ary[Redis_CONST::Play_Field_Circle] = $circle;
		$mset_result = $Redis_Model->hmsetField($Play_Key,$parameter_ary);
		return true;
	}

	//获取游戏中的用户
	protected function queryPlayMember($room_id){
		return $this->queryRoomMembers($room_id);
	}

	//获取房间玩法设置
	protected function queryRoomSetting($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$result = $Redis_Model->hgetallField($Room_Key);
		return $result;
	}

	//设置用户叫分倍数
	protected function updatePlayerChip($room_id, $account_id, $position_index, $chip){
		$Redis_Model = Redis_Model::getModelObject();
		$mkv[$account_id] = $chip;
		$mkv['t_'.$account_id] = microtime(true);
		$Redis_Model->hmsetField("Chip".$position_index.":".$room_id,$mkv);
		return true;
	}

	//获取用户叫分倍数
	protected function queryGrabMultiples($room_id, $account_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Grab_Key = strtr(Redis_Const::Grab_Key, $replyArr);
		$multiples = $Redis_Model->hgetField($Grab_Key, $account_id);
		return $multiples;
	}
	//设置用户叫分倍数
	protected function updateGrabMultiples($room_id, $account_id,$multiples){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Grab_Key = strtr(Redis_Const::Grab_Key, $replyArr);
		$mkv[$account_id] = $multiples;
		$Redis_Model->hmsetField($Grab_Key,$mkv);
		return true;
	}

	//获取上庄分数
	protected function queryBankerScore($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_BankerScore);
		return $result;
	}
	//设置上庄分数
	protected function updateBankerScore($room_id,$score){
		if($score < 0){
			return false;
		}
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$mkv[Redis_Const::Room_Field_BankerScore] = $score;
		$mset_result = $Redis_Model->hmsetField($Room_Key,$mkv);
		return true;
	}

	
	/***********************************
			commom_function
	***********************************/

	//推消息
	protected function pushMessageToGroup($room_id, $msg_arr, $exclude_client_id=null){
		$msg = $this->_JSON($msg_arr);
		Gateway::sendToGroup($room_id, $msg, $exclude_client_id);
	}
	protected function pushMessageToAccount($account_id, $msg_arr){
		$msg = $this->_JSON($msg_arr);
		Gateway::sendToUid($account_id, $msg);
	}
	protected function pushMessageToCurrentClient($msg_arr){
		$msg = $this->_JSON($msg_arr);
		Gateway::sendToCurrentClient($msg);
	}



	protected function getGameAnnouncement($account_id)
	{
		$timestamp = time();

		$MMYSQL = $this->initMysql();

		$game_type = Game::Game_Type;

		$announcement_where = 'game_type='.$game_type.' and announce_time<='.$timestamp.' and end_time>'.$timestamp.' and is_delete=0';
		$announcement_sql = 'select announce_time,service_time,end_time,announce_text,service_text from '.Game_Announcement.' where '.$announcement_where;
		$announcement_query = $MMYSQL->query($announcement_sql);
		if(is_array($announcement_query) && count($announcement_query) > 0)
		{
			$announce_time = $announcement_query[0]['announce_time'];
			$service_time = $announcement_query[0]['service_time'];
			$end_time = $announcement_query[0]['end_time'];
			$announce_text = $announcement_query[0]['announce_text'];
			$service_text = $announcement_query[0]['service_text'];

			if($timestamp >= $service_time)
			{
				$array['alert_type'] = 4;
				$array['alert_text'] = $service_text;
			}
			else
			{
				$array['alert_type'] = 4;
				$array['alert_text'] = $announce_text;
			}

			//获取白名单用户
			$whilelist_sql = 'select data_id from '.Game_Whilelist.' where account_id='.$account_id.' and is_delete=0';
			$whilelist_query = $MMYSQL->query($whilelist_sql);
			if(is_array($whilelist_query) && count($whilelist_query) > 0)
			{
				$this->logMessage('error', "function(getGameAnnouncement):白名单用户:".$account_id." in file".__FILE__." on Line ".__LINE__);
				return true;
			}
			else
			{
				return $array;
			}
		}

		return true;
	}


	
	protected function setHashTransaction($room_id)
	{
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$key = strtr(Redis_Const::Room_Key, $replyArr);

		$redisAuth = $Redis_Model->pingRedisAuth();
		if($redisAuth === G_CONST::EMPTY_STRING || !is_object($redisAuth))
		{
			$this->logMessage('error', "function(setHashTransaction):redisAuth is empty string"." in file".__FILE__." on Line ".__LINE__);
			return false;
		}

	    $success = false;
	    $options = array(
	        'cas'   => true,    // Initialize with support for CAS operations
	        'watch' => $key,    // Key that needs to be WATCHed to detect changes
	        'retry' => 3,       // Number of retries on aborted transactions, after
	                            // which the client bails out with an exception.
	    );

	    $redisAuth->transaction($options, function ($tx) use ($key, &$success) {
	        $room_status = $tx->hget($key, Redis_Const::Room_Field_Status);
	        if (isset($room_status) && $room_status == 1) {
	            $tx->multi();   // With CAS, MULTI *must* be explicitly invoked.
	            $tx->hmset($key, array(Redis_Const::Room_Field_Status => 2));
	            $success =  true;

	        } else {
	        	//echo "room_status != 1".PHP_EOL;
	        	$this->logMessage('error', "function(setHashTransaction):room_status error "." in file".__FILE__." on Line ".__LINE__);
	        	$success =  false;
	        }
	    });
	    return $success;
	}

	//设置游戏圈数
	protected function setCircleTransaction($room_id,$check_circle,$update_circle)
	{

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$key = strtr(Redis_Const::Play_Key, $replyArr);
		
		$redisAuth = $Redis_Model->pingRedisAuth();
		if($redisAuth === G_CONST::EMPTY_STRING || !is_object($redisAuth))
		{
			$this->logMessage('error', "function(setCircleTransaction):redisAuth is empty string"." in file".__FILE__." on Line ".__LINE__);
			return false;
		}

	    $success = false;
	    $options = array(
	        'cas'   => true,    // Initialize with support for CAS operations
	        'watch' => $key,    // Key that needs to be WATCHed to detect changes
	        'retry' => 3,       // Number of retries on aborted transactions, after
	                            // which the client bails out with an exception.
	    );

	    $redisAuth->transaction($options, function ($tx) use ($key,$check_circle,$update_circle, &$success) {
	        $paly_circle = $tx->hget($key, Redis_CONST::Play_Field_Circle);
	        if (isset($paly_circle) && $paly_circle == $check_circle) {
	            $tx->multi();   // With CAS, MULTI *must* be explicitly invoked.
	            $tx->hmset($key, array(Redis_Const::Play_Field_Circle => $update_circle));
	            $success =  true;

	        } else {
	        	//echo "paly_circle != ".$check_circle.PHP_EOL;
	        	$this->logMessage('error', "function(setCircleTransaction):play_circle error ".$check_circle." in file".__FILE__." on Line ".__LINE__);
	        	$success =  false;
	        }
	    });
	    return $success;
	}


	/*
		数组转JSON格式
	*/
	protected function _JSON($array) 
	{  
		$this->__arrayRecursive($array, 'urlencode', true);  
		$json = json_encode($array);  
		return urldecode($json);  
	}
	private function __arrayRecursive(&$array, $function, $apply_to_keys_also = false)  
	{  
		static $recursive_counter = 0;  
		if (++$recursive_counter > 1000) {  
			die('possible deep recursion attack');  
		}  
		foreach ($array as $key => $value) {  
			if (is_array($value)) {  
				$this->__arrayRecursive($array[$key], $function, $apply_to_keys_also);  
			}
			else if(is_object($value))
			{
				$array[$key] = $value;
			} 
			else 
			{  
				$array[$key] = $function($value);  
			}  
	   
			if ($apply_to_keys_also && is_string($key)) {  
				$new_key = $function($key);  
				if ($new_key != $key) {  
					$array[$new_key] = $array[$key];  
					unset($array[$key]);  
				}  
			}  
		}  
		$recursive_counter--;
	}   
	
	/**
    * 拆解接收的json字符串
    * @param string $splitJsonString json字符串
    */
	protected function _splitJsonString($jsonString)
	{
		if(empty($jsonString))
		{
			return OPT_CONST::JSON_FALSE;
		}
		//判断是否为JSON格式
		if(is_null(json_decode($jsonString)))
		{
			//不是json格式
			return OPT_CONST::JSON_FALSE;
		}
		else
		{
			//分拆JSON字符串
			return json_decode($jsonString,true);
		}
	}
	
	/*
		返回缺参结果
	*/
	protected function _missingPrameterArr($operation,$prameter)
	{
		return array('result'=>OPT_CONST::MISSING_PARAMETER,'operation'=>$operation,'data'=>array("missing_parameter"=>$prameter),'result_message'=>"缺少参数");
	}
	
	
	/*
		判断数据格式是否正确
	*/
	protected function _checkRequestFormat($requestAry)
	{
		if(!isset($requestAry['msgType']))
		{
			$this->logMessage('error', "function(checkRequestFormat):lack of msgType"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>"",'data'=>array("missing_parameter"=>"msgType"),'result_message'=>"缺少参数");
		}
		if(!isset($requestAry['content']))
		{
			$this->logMessage('error', "function(checkRequestFormat):lack of content"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>"",'data'=>array("missing_parameter"=>"content"),'result_message'=>"缺少参数");
		}
		
		return OPT_CONST::POSTARRAY_TRUE;
	}
	
	/*
		判断数据格式是否正确
	*/
	protected function _checkPostArray($postArr)
	{
		
		if(!isset($postArr['operation']))
		{
			$this->logMessage('error', "function(checkPostArray):lack of operation"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>"",'data'=>array("missing_parameter"=>"operation"),'result_message'=>"缺少参数");
		}
		else $operation = $postArr['operation'];
		if(!isset($postArr['data']))
		{
			$this->logMessage('error', "function(checkPostArray):lack of data"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>$operation,'data'=>array("missing_parameter"=>"data"),'result_message'=>"缺少参数");
		}
		if(!isset($postArr['account_id']))
		{
			$this->logMessage('error', "function(checkPostArray):lack of account_id"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>$operation,'data'=>array("missing_parameter"=>"account_id"),'result_message'=>"缺少参数");
		}
		return OPT_CONST::POSTARRAY_TRUE;
	}
	
	
	/*
		生成微秒
	*/
	protected function getMicroTimestamp()
	{
		$mtime=explode(' ',microtime());
		$mTimestamp=$mtime[1] . substr($mtime[0],2,3);
		
		return $mTimestamp;
	}
	
	
	
}
?>